<template>
  <div style="width: 100%">
    <component
      v-if="currentComponent"
      style="width: 100%"
      clearable
      startPlaceholder="开始日期"
      endPlaceholder="结束日期"
      v-bind="{
        ...currentComponent,
        ...data,
        ...props[currentComponent.config],
        onChange: (value) =>
          onChangeValue(value, props[currentComponent.config]),
      }"
      v-model="formParam[data.key || data.prop]"
      :is="currentComponent.component"
      :placeholder="
        data.p || data.placeholder || `${rulesMessage[data.type]}${data.label}`
      "
      :data="findConfig(data.option, optionConfig)"
      :options="findConfig(data.option, optionConfig)"
      :props="data?.fieldNames || fieldNames"
      :filter-node-method="
        (value, data) => filterNodeMethod(value, data, data.searchKey)
      "
      :disabled="isDisabled(data.row)"
    >
      <template #default v-if="data.type === 'select'">
        <el-option
          v-for="v in findConfig(data.option, optionConfig)"
          :key="v[data?.fieldNames?.value] || v[fieldNames?.value]"
          :label="v[data?.fieldNames?.label] || v[fieldNames?.label]"
          :value="v[data?.fieldNames?.value] || v[fieldNames?.value]"
        />
      </template>
    </component>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";
import {
  config,
  propsConfig,
  findConfig,
  fieldNames,
  rulesMessage,
} from "./index";

const emit = defineEmits(["changeValue"]);
const props = defineProps({
  data: { type: Object, required: true, default: () => ({}) },
  ...propsConfig,
});

// 避免模板中频繁的 v-if 判断，使用 computed 计算属性
const currentComponent = computed(() => {
  return config.find((item) => item.type === props.data.type);
});

// tree搜索
const filterNodeMethod = (value, data, searchKey = "label") =>
  data[searchKey].includes(value);

// 封装禁用状态判断逻辑，使用 “===” 会导致数字和字符串不相等
// row：表格当前行数据，data：当前组件数据，form表单不包含record
const isDisabled = (row = null) => {
  const { data, disabledConfig } = props;
  const target = row || data;
  if (typeof data.disabled === "function") {
    return data.disabled({ row: target });
  }
  if (typeof data.disabled === "string") {
    // disabledKeys和disabled都存在时，进行对比相同则禁用
    if (target[data.disabledKeys] && disabledConfig[data.disabled]) {
      return !(target[data.disabledKeys] == disabledConfig[data.disabled]);
    }
    // 优先从 disabledConfig 获取外部控制状态
    if (disabledConfig && disabledConfig.hasOwnProperty(data.disabled)) {
      if (typeof disabledConfig[data.disabled] === "boolean") {
        return disabledConfig[data.disabled];
      }
      // 为字符串返回false，防止报错只接受布尔值
      return false;
    }
    // 字段级联动禁用规则：通过 record 的 key 匹配值是否相等并取反
    // 不相等则禁用，相等则打开，根据需求自行调整
    return !(target[data.disabledKeys] == target[data.disabled]);
  }
  // 直接返回静态禁用状态（Boolean），!!用于确保返回布尔值
  return !!data.disabled;
};

// 选择器：获取选中的完整数据项（id, name 等）
const getSelectedOption = (selectData) => {
  const { data, optionConfig } = props;
  const { value, children } = data?.fieldNames || fieldNames;
  const options = findConfig(data.option, optionConfig);
  if (!options) return null;
  // 根据选中的 value 获取对应的完整数据项（id, name 等）
  const findOption = (options, val) => {
    for (let option of options) {
      if (option[value] === val) {
        return option;
      }
      if (option[children]) {
        const result = findOption(option[children], val);
        if (result) return result;
      }
    }
    return null;
  };
  return findOption(options, selectData);
};
// 输入框/选择器事件
const onChangeValue = (value, configs = {}) => {
  const { data, formParam } = props;
  /**
   * el不支持当前选中返回所有数据，只返回value（id）
   * 对选择器进行筛选，返回完整数据项（id, name 等）
   */
  const id = Array.isArray(value) ? value[value?.length - 1] : value;
  const option = getSelectedOption(id);
  // 简单的处理
  if (data?.change) {
    return data.change(formParam, { value, option });
  }
  // 如果 args对象 存在，根据 key:'value' 进行赋值操作
  const args = data?.param || data?.params;
  // 日期类型，返回数组，需要单独处理
  const dateType = ["daterange", "datetimerange", "monthrange"];
  if (args) {
    if (dateType.includes(data.type)) {
      for (const [index, item] of args.entries()) {
        formParam[item] = value?.[index];
      }
      return;
    }
    for (const key in args) {
      formParam[key] = option?.[args[key]];
    }
    return; // 可选
  }
  // 返回默认参数
  const { onChange } = configs;
  const datas = { ...data, value, option };
  const currentValue = configs[datas.key || datas.prop];
  /**
   * onChange：不根据字段，全部返回
   * currentValue：根据字段返回，只做当前处理
   */
  const events = currentValue || onChange;
  if (events) {
    return events(datas);
  }
  // 传递给父组件
  emit("changeValue", datas);
};
</script>

<style lang="scss" scoped>
// 日期区间选择器溢出问题
:deep(.el-range__icon) {
  padding-left: 10px;
}
:deep(.el-range__close-icon) {
  padding-right: 10px;
}
</style>